// workerPool.ts
export class WorkerPool<TTask, TResult> {
  private size: number;
  private workers: Worker[] = [];
  private idle: Worker[] = [];
  private queue: { task: TTask; resolve: (v: TResult) => void; reject: (e: any) => void }[] = [];
  private handler: (worker: Worker, task: TTask) => void;

  constructor(size: number, workerFactory: () => Worker, handler: (worker: Worker, task: TTask) => void) {
    this.size = size;
    this.handler = handler;
    for (let i = 0; i < size; i++) {
      const w = workerFactory();
      this.workers.push(w);
      this.idle.push(w);
    }
  }

  warmup(dummyTask?: TTask) {
    // 可以投递1个极轻任务促使浏览器下载与编译 worker 模块
    if (!dummyTask) return;
    void this.run(dummyTask).catch(() => void 0);
  }

  run(task: TTask): Promise<TResult> {
    return new Promise((resolve, reject) => {
      this.queue.push({ task, resolve, reject });
      this.pump();
    });
  }

  private pump() {
    while (this.idle.length && this.queue.length) {
      const w = this.idle.pop()!;
      const { task, resolve, reject } = this.queue.shift()!;
      const onMessage = (e: MessageEvent) => {
        w.removeEventListener("message", onMessage);
        w.removeEventListener("error", onError);
        this.idle.push(w);
        resolve(e.data as TResult);
        // 释放主线程执行权，降低长时间占用
        setTimeout(() => this.pump(), 0);
      };
      const onError = (e: ErrorEvent) => {
        w.removeEventListener("message", onMessage);
        w.removeEventListener("error", onError);
        this.idle.push(w);
        reject(e.error || e.message);
        setTimeout(() => this.pump(), 0);
      };
      w.addEventListener("message", onMessage, { once: true });
      w.addEventListener("error", onError, { once: true });
      this.handler(w, task);
    }
  }

  terminate() {
    for (const w of this.workers) w.terminate();
    this.workers = [];
    this.idle = [];
    this.queue = [];
  }
}
